#include <iostream>
#include "SymTable.h"

#define TABLE_SIZE 1024

SymTable::SymTable() {
	this->mEntries = new SymTabEntry*[TABLE_SIZE];
	for(int i = 0; i < TABLE_SIZE; i++)
	{
		this->mEntries[i] = 0;
	}
	this->mMemory = new StringTab();
}

SymTable::~SymTable(){
	delete[] this->mEntries;
}

Key* SymTable::insert(char* lexem, TTypes::TType type)
{
	int hash = this->hashcode(lexem);
	Key* hashKey;

	// Falls kein Eintrag  an der hash-Stelle in der Tabelle
	if(this->mEntries[hash] == 0){
		char* myLexem = this->mMemory->insert(lexem, this->getLexemSize(lexem));
		Information* info = new Information(myLexem, type);
		this->mEntries[hash] = new SymTabEntry(info);
		hashKey = new Key(hash, myLexem);
	}
	// Falls bereits Eintr�ge an der hash-Stelle in der Tabelle
	else{
		SymTabEntry* lastEntry;
		SymTabEntry* currentEntry = this->mEntries[hash];

		// �berpr�fe ob lexem schon vorhanden ist
		do{
			if(compareLexem(currentEntry->getInfo()->getLexem(), lexem)){
				// Falls ja, Key zur�ckgeben
				return hashKey;
			}
			lastEntry = currentEntry;
			currentEntry = currentEntry->getNext();
		}while(currentEntry != 0);

		// Falls nein, Eintrag erstellen
		char* myLexem = this->mMemory->insert(lexem, this->getLexemSize(lexem));
		Information* info = new Information(myLexem, type);
		lastEntry->setNext(new SymTabEntry(info));
		hashKey = new Key(hash, myLexem);
	}
	return hashKey;
}

bool SymTable::compareLexem(char* string1, char* string2){
	int i = 0;
	bool same = true;
	do{
		if(string1[i] != string2[i])
		{
			same = false;
		}
	} while(string1[i++] != '\0' && same);
	return same;
}

int SymTable::getLexemSize(const char* lexem){
	int i = 0;
	while(lexem[i] != '\0'){
		++i;
	}
	return i;
}

Information* SymTable::lookup(Key* key){

	// Falls kein Eintrag gefunden wurde
	SymTabEntry* currentEntry = this->mEntries[key->getHash()];
	if(currentEntry == 0){
		return 0;
	}

	// Andernfalls suche Lexem
	do{
		if(this->compareLexem(currentEntry->getInfo()->getLexem(), key->getLexem())){
			// Falls Lexem gefunden
			return currentEntry->getInfo();
		}
		currentEntry = currentEntry->getNext();
	}while(currentEntry != 0);

	// Falls kein passendes Lexem gefunden wurde
	return 0;
}

int SymTable::hashcode(const char* lexem) const
{
	char lastChar;
	int i = 0;
	while (lexem[i] != '\0')
	{
		lastChar = lexem[i];
		i++;
	}
	return (int)((16 * lexem[0] + 8 * lastChar + 26 * i) % TABLE_SIZE);
}

void SymTable::printMemory(){
	for(int i = 0; i < TABLE_SIZE; i++)
	{
		if(this->mEntries[i] != 0)
		{
			SymTabEntry* currentEntry = this->mEntries[i];
			int counter = 0;
			do{
				//print me
				for(int j= 0; j < counter; j++){
					std::cout << "\t";
				}
				std::cout << currentEntry->getInfo()->getLexem() << std::endl;
				currentEntry = currentEntry->getNext();
				++counter;
			}while(currentEntry != 0);
		}
	}
}
